package com.bsg.upm.service;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.check.CheckResult;
import com.bsg.upm.check.SoftwareImageCheck;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.OperateDictConstants;
import com.bsg.upm.constant.OperateDictTypeConstants;
import com.bsg.upm.constant.SubTaskDictConstants;
import com.bsg.upm.constant.SysConstants;
import com.bsg.upm.constant.TaskDictConstants;
import com.bsg.upm.constant.TaskDictTypeConstants;
import com.bsg.upm.dto.SubServSoftwareImageDto;
import com.bsg.upm.entity.DefinitionSubServSoftwareEntity;
import com.bsg.upm.entity.DefinitionSubTaskConfigEntity;
import com.bsg.upm.entity.OperateLogEntity;
import com.bsg.upm.entity.SiteEntity;
import com.bsg.upm.entity.SubServSoftwareImageEntity;
import com.bsg.upm.entity.SubTaskEntity;
import com.bsg.upm.entity.TaskEntity;
import com.bsg.upm.entity.UserEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.HttpClientUtils;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.http.RespJsonFactory;
import com.bsg.upm.util.DateUtils;
import com.bsg.upm.util.PrimaryKeyUtils;

/**
 * 软件镜像管理业务处理类
 * 
 * @author HCK
 *
 */
@Service
public class SoftwareImageService extends BaseService {

	@Resource
	private SoftwareImageCheck softwareImageCheck;

	/**
	 * 软件镜像查询
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson list(Map<String, Object> paramMap) throws APIException {
		try {
			// 结果集
			JSONArray results = new JSONArray();

			// 获取指定条件的软件镜像
			List<SubServSoftwareImageEntity> subServSoftwareImages = subServSoftwareImageDao.list(paramMap);

			for (SubServSoftwareImageEntity softwareImage : subServSoftwareImages) {
				// 构建软件镜像展示对象
				SubServSoftwareImageDto softwareImageDto = buildShowDto(softwareImage, false);
				results.add(softwareImageDto);
			}

			return RespJsonFactory.buildOK(results);
		} catch (Exception e) {
			logger.error("软件镜像查询异常", e);
			throw new APIException("软件镜像查询异常:" + e.getMessage());
		}
	}

	/**
	 * 软件镜像详情
	 * 
	 * @param imageId
	 *            软件镜像编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson get(String imageId) throws APIException {
		try {
			// 获取指定的软件镜像
			SubServSoftwareImageEntity subServSoftwareImage = subServSoftwareImageDao.get(imageId);

			if (subServSoftwareImage == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该软件镜像不存在");
			}

			// 构建软件镜像展示对象
			SubServSoftwareImageDto softwareImageDto = buildShowDto(subServSoftwareImage, true);

			return RespJsonFactory.buildOK(softwareImageDto);
		} catch (Exception e) {
			logger.error("软件镜像获取异常", e);
			throw new APIException("软件镜像获取异常:" + e.getMessage());
		}
	}

	/*************************** add by ycs (start) ***************************/
	/**
	 * 获取软件模板配置
	 * 
	 * @param imageId
	 *            软件镜像编码
	 * @return 操作结果
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson getTemplateKeySets(String imageId) throws APIException {
		try {
			SubServSoftwareImageEntity subServSoftwareImage = subServSoftwareImageDao.get(imageId);
			if (subServSoftwareImage == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该软件镜像不存在");
			}

			String relateId = subServSoftwareImage.getRelateId();
			String siteId = subServSoftwareImage.getSite().getId();
			JSONObject respone = getTemplateFromMGM(relateId, siteId);
			if (respone.isEmpty()) {
				return RespJsonFactory.buildOK(null);
			}

			return RespJsonFactory.buildOK(respone.getJSONObject("config_template").getJSONArray("keysets"));

		} catch (Exception e) {
			logger.error("软件模板获取异常", e);
			throw new APIException("软件模板获取异常:" + e.getMessage());
		}
	}

	public RespJson updateTemplateKeysets(String imageId, JSONArray keysetJsonArr) throws APIException {
		try {
			SubServSoftwareImageEntity subServSoftwareImage = subServSoftwareImageDao.get(imageId);
			if (subServSoftwareImage == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该软件镜像不存在");
			}

			String relateId = subServSoftwareImage.getRelateId();
			String siteId = subServSoftwareImage.getSite().getId();
			JSONObject respone = getTemplateFromMGM(relateId, siteId);

			JSONObject template = respone.getJSONObject("config_template");

			template.put("keysets", keysetJsonArr);

			updatetTemplateToMGM(relateId, siteId, template);

			return RespJsonFactory.buildOK();

		} catch (Exception e) {
			logger.error("updateTemplateKeysets fail:", e);
			throw new APIException("updateTemplateKeysets fail:" + e.getMessage());
		}
	}

	/*************************** add by ycs (end) ***************************/

	/**
	 * 软件镜像新增
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常
	 */
	public RespJson save(Map<String, Object> paramMap) throws APIException {
		// 事务定义
		DefaultTransactionDefinition def = null;
		// 事务状态
		TransactionStatus txStatus = null;

		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_ADD;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 软件镜像新增检查
			CheckResult chkRS = softwareImageCheck.checkSave(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			def = new DefaultTransactionDefinition();
			def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
			txStatus = txManager.getTransaction(def);

			// 构建软件镜像对象
			SubServSoftwareImageEntity softwareImage = buildSubServSoftwareImage(paramMap);
			subServSoftwareImageDao.save(softwareImage);

			// 获取软件镜像名称
			String softwareImageName = getSoftwareImageNameAndVersion(softwareImage);
			// 保存操作日志
			OperateLogEntity operateLog = saveOperateLog(OperateDictConstants.MODEL_SOFTWARE_IMAGE, operateAcion,
					softwareImage.getId(), softwareImageName, softwareImage.getCreateDateTime());

			// 构建软件镜像创建任务
			TaskEntity task = buildCreateImageTask(softwareImage, operateLog);
			saveTask(task);
			txManager.commit(txStatus);

			// 开启任务
			startTask(task);
			return RespJsonFactory.buildCreated();
		} catch (Exception e) {
			if (txStatus != null) {
				txManager.rollback(txStatus);
			}
			logger.error("软件镜像" + operateAcionText + "异常", e);
			throw new APIException("软件镜像" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 软件镜像启用/停用
	 * 
	 * @param id
	 *            软件镜像编码
	 * @param enable
	 *            是否启用
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson enable(String id, boolean enable) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_DISABLE;
		if (enable) {
			operateAcion = OperateDictConstants.ACTION_ENABLE;
		}
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的软件镜像
			SubServSoftwareImageEntity softwareImage = subServSoftwareImageDao.get(id);

			// 软件镜像启停检查
			CheckResult chkRS = null;
			if (enable) {
				chkRS = softwareImageCheck.checkEnable(softwareImage);
			} else {
				chkRS = softwareImageCheck.checkDisable(softwareImage);
			}
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 设置启停状态
			softwareImage.setEnabled(enable);
			subServSoftwareImageDao.updateEnabled(softwareImage);

			// 获取软件镜像名称
			String softwareImageName = getSoftwareImageNameAndVersion(softwareImage);
			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_SOFTWARE_IMAGE, operateAcion, softwareImage.getId(),
					softwareImageName);

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("软件镜像" + operateAcionText + "异常", e);
			throw new APIException("软件镜像" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 软件镜像删除
	 * 
	 * @param id
	 *            软件镜像编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson remove(String id) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_REMOVE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的软件镜像
			SubServSoftwareImageEntity softwareImage = subServSoftwareImageDao.get(id);

			// 删除检查
			CheckResult chkRS = softwareImageCheck.checkRemove(softwareImage);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			subServSoftwareImageDao.remove(id);

			if (StringUtils.isNotBlank(softwareImage.getRelateId())) {
				// 从MGM上删除软件
				removeImageFromMGM(softwareImage.getSite().getId(), softwareImage.getRelateId());
			}

			// 获取软件镜像名称
			String softwareImageName = getSoftwareImageNameAndVersion(softwareImage);
			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_SOFTWARE_IMAGE, operateAcion, softwareImage.getId(),
					softwareImageName);

			return RespJsonFactory.buildNoContent();
		} catch (Exception e) {
			logger.error("软件镜像" + operateAcionText + "异常", e);
			throw new APIException("软件镜像" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 从MGM上删除软件
	 * 
	 * @param siteId
	 *            站点编码
	 * @param mgmImageId
	 *            mgm软件镜像编码
	 * @throws APIException
	 *             API异常处理类
	 */
	private void removeImageFromMGM(String siteId, String mgmImageId) throws APIException {
		String urlPattern = "/{0}/softwares/images/{1}";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, mgmImageId);
		RespJson httpRespJson = sendHttpDelete(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() != HttpStatus.SC_NO_CONTENT) {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 构建软件镜像展示对象
	 * 
	 * @param softwareImage
	 *            软件镜像编码
	 * @param showDetail
	 *            是否展示详情
	 * @return 软件镜像展示对象
	 */
	private SubServSoftwareImageDto buildShowDto(SubServSoftwareImageEntity softwareImage, boolean showDetail) {
		SubServSoftwareImageDto softwareImageDto = new SubServSoftwareImageDto();
		SiteEntity site = softwareImage.getSite();
		softwareImageDto.setSiteId(site.getId());
		softwareImageDto.setSiteName(site.getName());
		softwareImageDto.setId(softwareImage.getId());
		DefinitionSubServSoftwareEntity dfSubServSoftware = softwareImage.getDefinitionSubServSoftware();
		softwareImageDto.setName(dfSubServSoftware.getDefinitionSubServName());
		softwareImageDto.setMajorVersion(dfSubServSoftware.getMajorVersion());
		softwareImageDto.setMinorVersion(dfSubServSoftware.getMinorVersion());
		softwareImageDto.setPatchVersion(softwareImage.getPatchVersion());
		softwareImageDto.setBuildVersion(softwareImage.getBuildVersion());
		softwareImageDto.setEnabled(softwareImage.isEnabled());
		softwareImageDto.setEnabledText(dictTypeCache.getTextFromCache(DictTypeConstants.STATUS_ENABLED,
				String.valueOf(softwareImage.isEnabled())));
		softwareImageDto.setDescription(softwareImage.getDescription());
		List<TaskEntity> tasks = softwareImage.getTasks();
		if (tasks != null && tasks.size() > 0) {
			softwareImageDto.setTaskStatus(tasks.get(0).getStatus());
			softwareImageDto.setTaskStatusText(dictTypeCache.getTextFromCache(TaskDictTypeConstants.TASK_STATUS,
					softwareImageDto.getTaskStatus()));
		}
		softwareImageDto.setCreateDateTime(DateUtils.dateTimeToString(softwareImage.getCreateDateTime()));
		softwareImageDto.setCreateLoginUserName(softwareImage.getCreateUserLoginName());
		return softwareImageDto;
	}

	/**
	 * 构建软件镜像对象
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return 软件镜像对象
	 */
	private SubServSoftwareImageEntity buildSubServSoftwareImage(Map<String, Object> paramMap) {
		SubServSoftwareImageEntity subServSoftwareImage = new SubServSoftwareImageEntity();
		subServSoftwareImage.setId(PrimaryKeyUtils.uniqueId());
		String dfSubServSoftwareId = (String) paramMap.get("definitionSubServSoftware");
		DefinitionSubServSoftwareEntity dfSubServSoftware = definitionSubServSoftwareDao.get(dfSubServSoftwareId);
		dfSubServSoftware.setId(dfSubServSoftwareId);
		subServSoftwareImage.setDefinitionSubServSoftware(dfSubServSoftware);
		subServSoftwareImage.setPatchVersion((Integer) paramMap.get("patchVersion"));
		subServSoftwareImage.setBuildVersion((Integer) paramMap.get("buildVersion"));
		SiteEntity site = new SiteEntity();
		site.setId((String) paramMap.get("site"));
		subServSoftwareImage.setSite(site);
		subServSoftwareImage.setEnabled(false);
		if (paramMap.containsKey("description")) {
			subServSoftwareImage.setDescription(StringUtils.trim((String) paramMap.get("description")));
		}
		subServSoftwareImage.setCreateDateTime(systemDao.getCurrentDateTime());
		UserEntity user = getUser();
		String username = user.getUsername();
		subServSoftwareImage.setCreateUserLoginName(username);
		return subServSoftwareImage;
	}

	/**
	 * 构建软件镜像创建任务
	 * 
	 * @param softwareImage
	 *            软件镜像对象
	 * @param operateLog
	 *            操作日志对象
	 * @return 任务对象
	 */
	private TaskEntity buildCreateImageTask(SubServSoftwareImageEntity softwareImage, OperateLogEntity operateLog) {
		TaskEntity task = new TaskEntity();
		task.setId(PrimaryKeyUtils.uniqueId());
		task.setSite(softwareImage.getSite());
		task.setObjType(TaskDictConstants.OBJ_TYPE_SOFTWARE_IMAGE);
		task.setObjId(softwareImage.getId());
		String softwareImageName = getSoftwareImageNameAndVersion(softwareImage);
		task.setObjName(softwareImageName);
		task.setObj(softwareImage);
		task.setActionType(TaskDictConstants.ACTION_TYPE_CREATE);
		task.setOperateLog(operateLog);
		UserEntity user = getUser();
		String username = user.getUsername();
		task.setOwner(username);
		task.setCreateUserLoginName(username);
		task.setStatus(TaskDictConstants.STATUS_CREATE_RUNNING);
		task.setStartDateTime(operateLog.getCreateDateTime());

		List<SubTaskEntity> subTasks = buildCreateImageSubTasks(softwareImage, task.getStartDateTime());
		task.setSubTasks(subTasks);

		return task;
	}

	/**
	 * 构建软件镜像创建子任务
	 * 
	 * @param softwareImage
	 *            软件镜像对象
	 * @param date
	 *            任务开始时间
	 * @return 子任务集合
	 */
	private List<SubTaskEntity> buildCreateImageSubTasks(SubServSoftwareImageEntity softwareImage, Date date) {
		List<SubTaskEntity> subTasks = new ArrayList<SubTaskEntity>(1);

		SubTaskEntity subTask = new SubTaskEntity();
		subTasks.add(subTask);

		subTask.setId(PrimaryKeyUtils.uniqueId());
		subTask.setObjType(SubTaskDictConstants.OBJ_TYPE_SOFTWARE_IMAGE);
		subTask.setObjId(softwareImage.getId());
		String softwareImageName = getSoftwareImageNameAndVersion(softwareImage);
		subTask.setObjName(softwareImageName);
		subTask.setObj(softwareImage);
		subTask.setActionType(SubTaskDictConstants.ACTION_TYPE_CREATE);
		subTask.setAsync(true);
		DefinitionSubTaskConfigEntity dfSubTaskConfig = definitionSubTaskConfigCache
				.getDfSubTaskConfigFromCache(subTask.getObjType(), subTask.getActionType());
		subTask.setTimeout(dfSubTaskConfig.getTimeout());
		subTask.setStatus(SubTaskDictConstants.STATUS_RUNNING);
		subTask.setStartDateTime(date);
		String url = "/" + SysConstants.MGM_VERSION + "/softwares/images";
		subTask.setUrl(url);
		subTask.setMethodType(HttpClientUtils.METHOD_POST);
		String param = buildParamForCreateImage(softwareImage);
		subTask.setParam(param);
		subTask.setPriority(1);
		return subTasks;
	}

	/**
	 * 构建软件镜像创建所需参数
	 * 
	 * @param softwareImage
	 *            软件镜像对象
	 * @return String 软件镜像创建所需参数
	 */
	private String buildParamForCreateImage(SubServSoftwareImageEntity softwareImage) {
		JSONObject jsonParam = new JSONObject();
		DefinitionSubServSoftwareEntity dfSubServSoftware = softwareImage.getDefinitionSubServSoftware();
		jsonParam.put("name", dfSubServSoftware.getDefinitionSubServName());
		jsonParam.put("major_version", dfSubServSoftware.getMajorVersion());
		jsonParam.put("minor_version", dfSubServSoftware.getMinorVersion());
		Integer pathVersion = softwareImage.getPatchVersion();
		jsonParam.put("patch_version", pathVersion);
		Integer buildVersion = softwareImage.getBuildVersion();
		jsonParam.put("build_version", buildVersion);
		String imagePath = getSoftwareImagePath(softwareImage);
		jsonParam.put("image_path", imagePath);
		return jsonParam.toJSONString();
	}

	/*************************** add by ycs (start) ***************************/
	private JSONObject getTemplateFromMGM(String relateimageId, String siteId) throws APIException {

		String url = String.format("/%s/softwares/images/%s", SysConstants.MGM_VERSION, relateimageId);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);

		if (httpRespJson.getStatus() != HttpStatus.SC_OK) {
			logger.error("getTemplateFromMGM fail:" + httpRespJson);
			throw new APIException(httpRespJson.getMsg());
		}

		return (JSONObject) httpRespJson.getData();

	}

	private void updatetTemplateToMGM(String relateimageId, String siteId, JSONObject templateObj) throws APIException {
		String url = String.format("/%s/softwares/images/%s", SysConstants.MGM_VERSION, relateimageId);
		RespJson httpRespJson = sendHttpPut(siteId, SysConstants.INTERFACE_TYPE_MGM, url, templateObj.toJSONString());

		if (httpRespJson.getStatus() != HttpStatus.SC_OK) {
			logger.error("updatetTemplateToMGM  fail:" + httpRespJson);
			throw new APIException(httpRespJson.getMsg());
		}
	}
	/*************************** add by ycs (end) ***************************/

}
